﻿using System;
using System.Configuration;
using System.Data.Common;
using System.IO;
using System.Web;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Xml.XPath;
using System.Xml.Xsl;
using Songhay.Data;
using Songhay.Data.Common;
using Songhay.Xml;

namespace Songhay.Web
{
    public partial class DataActivtyServer : HttpApplication
    {
        /// <summary>
        /// Loads the default layout for the Client.
        /// </summary>
        /// <param name="Client">
        /// The ASP.NET <see cref="System.Web.UI.Page"/>.
        /// </param>
        /// <remarks>
        /// This procedure defines the following conventions:
        /// 
        /// The ASP.NET <see cref="System.Web.UI.Page"/> must have block elements
        /// <c>CommandBlock</c> and <c>DisplayBlock</c>.
        /// 
        /// The ASP.NET <see cref="System.Web.UI.Page"/> must have an Application Property
        /// called <c>DataConnectionId</c>.
        /// 
        /// The ASP.NET <see cref="System.Web.UI.Page"/> must refer to a CSS class
        /// called <c>ServerError</c>.
        /// 
        /// The conventional XSLT file <c>Client.xslt</c> must have a parameter
        /// called <c>cmd</c> that responds to the value <c>DataConnections</c>
        /// assigned to this parameter.
        /// 
        /// The <c>DataAccessConfiguration.xml</c> file must contain at least one
        /// <c>DataAccessItem</c> with one <c>NameValuePair</c> with <c>Name="default"</c>.
        /// 
        /// </remarks>
        public static void LoadClient(Page Client, HttpContext Context)
        {
            DataActivtyServer._log.AppendLine("Loading client...");

            HtmlGenericControl c;
            HtmlInputHidden h;

            string s;

            string cmdBname = "CommandBlock"; //Conventional command block on Client.
            string disBname = "DisplayBlock"; //Conventional display block on Client.
            string dataIdInput = "DataConnectionId"; //Conventional data connection ID in Client application properties.
            string serverMessageBlock = "<pre class=\"ServerError\">{0}</pre>"; //Refers to conventional CSS class name.

            DataActivtyServer._log.AppendLine(String.Format("Looking for client command block {0}...", cmdBname));
            c = Client.FindControl(cmdBname) as HtmlGenericControl;
            if(c != null)
            {
                try
                {
                    DataActivtyServer._log.AppendLine("Rendering client from XSL data...");
                    s = XmlUtility.LoadXslTransform(DataActivtyServer._clientXsl, cmdBname, "<nothing />");
                    c.InnerHtml = XmlUtility.StripNamespaces(s);
                }
                catch(Exception ex)
                {
                    s = XmlUtility.GetInternalMessage("Exception for Client Load",
                        new String[] { String.Format(serverMessageBlock, ex.Message), ex.StackTrace, DataActivtyServer._log.ToString() });
                    s = XmlUtility.LoadXslTransform(DataActivtyServer._clientXsl, String.Empty, s);
                    if(c != null) c.InnerHtml = s;
                }
            }

            DataActivtyServer._log.AppendLine(String.Format("Looking for client display block {0}...", cmdBname));
            c = Client.FindControl(disBname) as HtmlGenericControl;
            if(c != null)
            {
                try
                {
                    RequestBag request = new RequestBag(Context);

                    if(String.IsNullOrEmpty(request.DataConnectionId))
                    {
                        DataActivtyServer._log.AppendLine("No data connection requested or found. Showing available connections...");

                        //Build conventional command to list data connections:
                        NameValuePair xslDataListArg = new NameValuePair();
                        xslDataListArg.Name = "cmd";
                        xslDataListArg.Value = "DataConnections";

                        XsltArgumentList args = new XsltArgumentList();
                        args.AddParam(xslDataListArg.Name, String.Empty, xslDataListArg.Value);
                        s = XmlUtility.LoadXslTransform(DataActivtyServer._clientXsl, args, DataActivtyServer._dbmsMetaXml);
                        c.InnerHtml = XmlUtility.StripNamespaces(s);
                    }
                    else
                    {
                        DataActivtyServer._log.AppendLine(String.Format("Loading default view for {0}...", request.DataConnectionId));

                        //Collect DBMS metadata:
                        DataAccessItem dbInfo = DataActivtyServer._dbmsMeta.GetDataAccessItem(request.DataConnectionId);
                        ICommandHandler dataCmd = DataActivtyServer._dataManagers[request.DataConnectionId];
                        String connectionString = dbInfo.Connection[0].ConnectionString;
                        String providerInvariantName = dbInfo.Connection[0].InvariantProviderName;

                        //Get conventional data command:
                        NameValuePair defaultDataCommand = dbInfo.GetNameValuePair("default");
                        if(defaultDataCommand == null) throw new ConfigurationErrorsException("The default data command was not found in the configuration file.");

                        //Get conventional XSLT file associated with data command:
                        NameValuePair defaultXsl = dbInfo.GetNameValuePair(defaultDataCommand.Value);
                        if(defaultXsl == null) throw new ConfigurationErrorsException("The default XSL information was not found in the configuration file.");

                        string xslpath = Client.Server.MapPath(defaultXsl.Value);
                        if(!File.Exists(xslpath)) throw new ConfigurationErrorsException(String.Format("XSL file “{0}” not found.", xslpath));

                        using(DbConnection cnn = CommonDbms.GetConnection(providerInvariantName, connectionString))
                        {
                            cnn.Open();

                            DataCommandInput input = new DataCommandInput();
                            input.CommandName = defaultDataCommand.Value;
                            input.DataConnection = cnn;

                            DataActivtyServer._log.AppendLine(String.Format("Running command {0}...", input.CommandName));
                            XPathDocument d = dataCmd.DoCommand(input);
                            s = d.CreateNavigator().OuterXml;
                            s = XmlUtility.LoadXslTransform(xslpath, input.CommandName, s);
                            c.InnerHtml = XmlUtility.StripNamespaces(s);
                        }

                        h = Client.FindControl(dataIdInput) as HtmlInputHidden;
                        if(h != null) h.Value = request.DataConnectionId;
                    }
                }
                catch(Exception ex)
                {
                    s = XmlUtility.GetInternalMessage("Exception for Client Load",
                        new String[] { String.Format(serverMessageBlock, XmlUtility.ExpandSpecialChars(ex.Message)), XmlUtility.ExpandSpecialChars(ex.StackTrace), XmlUtility.ExpandSpecialChars(DataActivtyServer._log.ToString()) });
                    s = XmlUtility.LoadXslTransform(DataActivtyServer._clientXsl, String.Empty, s);
                    if(c != null) c.InnerHtml = s;
                }
            }
        }
    }
}